/**  
 * Copyright (c) 2010 University of Pennsylvania.
 *     All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an "AS
 *  IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 *  express or implied.  See the License for the specific language
 *  governing permissions and limitations under the License.
 *
 */
 
#ifdef MINIMUM_MEMORY
  #define MAX_FORWARDDATASIZE     20  // max size of forward msgs payload
  #define FORWARDBUFFER_SIZE       5  // maximum number of source routes through a node (with eviction)
  #define MERGEBUFFER_SIZE        10  // size of merge buffer for forward msgs
  #define SUBSCRIBEBUFFER_SIZE     5  // max number of waiting path requests
  #define PATHCACHE_SIZE           5  // max number of cached paths through a node (can serve requests instantly)
  #define REPAIRPATH_SIZE          5  // max number of path destination repairs per node
  #define REPAIRQUEUE_SIZE         5  // max number of messages to queue up while doing repair
  #define PATHCOLLAPSEBUFFER_SIZE  5  // max path collapse optimization decision to remember
  #define MULTICASTBUFFER_SIZE    30    // maximum size of multicast buffer
#else
  #define MAX_FORWARDDATASIZE     50
  #define FORWARDBUFFER_SIZE      10
  #define MERGEBUFFER_SIZE        50
  #define SUBSCRIBEBUFFER_SIZE    10
  #define PATHCACHE_SIZE          10
  #define REPAIRPATH_SIZE         20
  #define REPAIRQUEUE_SIZE        10
  #define PATHCOLLAPSEBUFFER_SIZE 10
  #define MULTICASTBUFFER_SIZE    75    
#endif

#define PATHSTATUS_REPAIRING   0    // if a path through a neighbor is broken, whats its status
#define PATHSTATUS_REPAIRED    1
#define PATHSTATUS_BROKEN      2

#define ROUTE_SUCCESS         0    // repair path not found
#define ROUTE_FAIL            1    // repair path found

#define FORWARD_DESTRUCTIVE    1    // destructive path vector for source routing
#define FORWARD_NONDESTRUCTIVE 0    // non destructive (circular) path vector for source routing

#define MERGEBUFFER_THROTTLE     3   // send that many msgs from merge buffer to output buffer at a time
#define MAX_EXCHANGECOUNT      4   // maximum entries of the forward buffer to be exchanged at a time
                                   // depends on how many bytes per address are marshalled

#define REPAIR_NONE            0   // no repair on forward msgs
#define REPAIR_SINGLETREE      1   // single tree repair (only to Base)
#define REPAIR_L1              2   // single tree repair + RepairRoute with summary on IDs of children
#define REPAIR_L2              3   // single tree + Repair Route with summary on children + neighbors

typedef struct {              // Message type for source routing (greedy forwarding)
  uint8_t cmd;

  ADDRESS source_node, dest_node;  // initiator and destination nodes
  uint8_t destructive, failed;   // 1 if pathvector is sent exhaustively, 0 if circular; failed - if we are returning undeliverable msg back to source

  uint8_t path_len;              // path vector length
  ADDRESS path[MAX_PATHLEN];     // path vector, source_node is not included, dest_node is.

  uint8_t data_len;              // length of payload
  uint8_t data[MAX_FORWARDDATASIZE];  // payload

  uint8_t multicastbuffer_len;   // specifies length of multicast tree encoding (if positive)
  uint8_t multicast_buffer[MULTICASTBUFFER_SIZE];  // multicast tree encoding
} PACKING_MACRO FORWARD_MSG;

typedef struct {              // message type for flow information exchange message
  uint8_t cmd;

  uint8_t entry_count;        // how many flows are we sending
  struct {
    ADDRESS source_node, dest_node, next_node;  // for each flow, source, target, and intermediate hops
    uint8_t hops;                               // number of hops to target
  } PACKING_MACRO entries[MAX_EXCHANGECOUNT];
} PACKING_MACRO FORWARDBUFFEREXCHANGE_MSG;

typedef struct {              // message type for remote path subscription
  uint8_t cmd;
                      // register subscription for a path from source_node2 to dest_node. source_node1 is key used by the sender
  ADDRESS source_node1, source_node2, dest_node;
} PACKING_MACRO PATHSUBSCRIBE_MSG;

typedef struct {             // message type for response to path subscription
  uint8_t cmd;

  ADDRESS source_node1, source_node2, dest_node;
  uint8_t path_len;          // Responding to subscription for a path from source_node2 to dest_node.
  ADDRESS path[MAX_PATHLEN]; // Only portion from current node to dest_node sent.
} PACKING_MACRO PATHRESPOND_MSG;

typedef struct {             // structure maintaining information for flows through the current node
  uint8_t used;
                            // flow, source, target and two intermediate hops (back and forward)
  ADDRESS source_node, dest_node, prev_node, next_node;
  uint8_t hops, modified;   // hops to destination; modified - if the entry has changed since we last aired it to our neighbors
  uint32_t msg_count;       // how many messages were sent on this flow,
} PACKING_MACRO FORWARDBUFFER_ENTRY;

typedef struct {             // remembers path collapse decision issued, so not to duplicate them
  uint8_t used;

  ADDRESS common_node, neighbor_node;
} PACKING_MACRO PATHCOLLAPSEBUFFER_ENTRY;

typedef struct {            // structure for of the data value merging buffer
  uint8_t used;

  uint8_t allow_merge;
  ADDRESS dest_node, prev_node, next_node;    // intermediate and last hops of the flow
  uint8_t *msg, msg_len;                      // marshalled message
  int16_t next, prev;       // next and previous entry on the same flow
} PACKING_MACRO MERGEBUFFER_ENTRY;

typedef struct {            // structure for maitaining path subscriptions
  uint8_t used;
                            // subsciption itself; subscriber_node - requesting neighbor
  ADDRESS source_node1, source_node2, dest_node, subscriber_node;
} PACKING_MACRO SUBSCRIBEBUFFER_ENTRY;

typedef struct {            // cache for paths, independent of flow exchange buffer
  uint8_t used;

  ADDRESS dest_node;    // flow: source - target
  uint8_t path_len;                  // length of cached path from current node to target
  ADDRESS *path;                     // path itself
} PACKING_MACRO PATHCACHE_ENTRY;

typedef struct {                     // structure for maintaing path repairs through a node
  uint8_t used;

  uint8_t path_status;               // PATHSTATUS_XXXXX constant
  ADDRESS neighbor_node, dest_node; // if you want to use neighbor_node to get to dest_node ...
  uint8_t path_len;                  // ... use this path instead.
  ADDRESS *path;
} PACKING_MACRO REPAIRPATH_ENTRY;

typedef struct {                     // structure for queueing messages while repair is in progress
  uint8_t used;

  ADDRESS neighbor_node, dest_node, prev_node; // queue messages needing to traverse neighbor_node, and going to dest_node
  uint8_t msg_len, *msg;             // marshalled FORWARD_MSG
} PACKING_MACRO REPAIRQUEUE_ENTRY;

FORWARDBUFFER_ENTRY forward_buffer[FORWARDBUFFER_SIZE];
PATHCOLLAPSEBUFFER_ENTRY pathcollapse_buffer[PATHCOLLAPSEBUFFER_SIZE];
MERGEBUFFER_ENTRY merge_buffer[MERGEBUFFER_SIZE];
uint8_t mergebuffer_size;
SUBSCRIBEBUFFER_ENTRY subscribe_buffer[SUBSCRIBEBUFFER_SIZE];
PATHCACHE_ENTRY path_cache[PATHCACHE_SIZE];

REPAIRPATH_ENTRY repair_path[REPAIRPATH_SIZE];
REPAIRQUEUE_ENTRY repair_queue[REPAIRQUEUE_SIZE];

void init_mforward();

uint8_t init_forward(ADDRESS source_node, ADDRESS prev_node, ADDRESS dest_node, uint8_t node_count,
  ADDRESS *nodes, uint8_t destructive, uint8_t data_len, uint8_t *data, uint8_t multicastbuffer_len,
  uint8_t *multicast_buffer, uint8_t failed);

void forward_message(ADDRESS source_id, FORWARD_MSG *msg);
void handle_forwardmsg(ADDRESS source_id, uint8_t *p);
void handlesent_forwardmsg(uint8_t msg_len, uint8_t *p, uint8_t send_success, uint8_t node_count,
  ADDRESS *nodes, uint8_t confirm_seq);
void handlesnoop_forwardmsg(ADDRESS source_id, ADDRESS dest_node, uint8_t *p,
  uint8_t fragment_count);  

void handle_forwardbufferexchangemsg(ADDRESS source_id, uint8_t *p);
void handle_pathsubscribemsg(ADDRESS source_id, uint8_t *p);
void handle_pathrespondmsg(ADDRESS source_id, uint8_t *p);

void update_mergebuffer();
void merge_forward(FORWARD_MSG *msg, ADDRESS prev_node, ADDRESS next_node, uint8_t allow_merge);

int find_repairpathindex(ADDRESS neighbor_node, ADDRESS dest_node);
void handlerepair_forwardmsgs(uint8_t repair_success, ADDRESS neighbor_node, ADDRESS dest_node);

void timer_forwardbufferexchange();
